package org.iori.util.text;

/**
 * The class for opreate CSV file.
 * <p>
 * The CSV file may include comment lines, blank lines and value lines. The
 * comment line starts with character '#' or ';'. The blank line only includes
 * whitespace character(s). Other lines are value lines.
 * <p>
 * Each line(include cpmment lines,etc.) is assigned a line number, based from
 * 0. The getLine() method can return each line regardless it is comment line or
 * value line, and the returned string is the original format as the CSV file.
 * <p>
 * The column is meaning only for the value lines. Using column methods to the
 * none value lines will do nothing.
 * <p>
 * The CSV file may be encoded with specified charset, default value is "SJIS"
 * for japanese, use setFileEncoding() to change to others.
 *
 * @author zhang_jianbin
 * @history
 *         <p>
 *         2006-3-27 Created Zhang Jianbin
 *         <p>
 *         2006-3-20 Modify extract the common methods to the superclass.
 */
public class CSVAccessor extends TXTFileAccessor {
	/**
	 * the column index of key value, based 0
	 */
	private int keyIndex;

	/**
	 * The standard column count for this CSV file.
	 */
	private int columnCount;

	/*
	 * (non-Javadoc)
	 *
	 * @see com.founder.siryodb.util.TXTFileAccessor#appendLine()
	 */
	@Override
	public int appendLine() {
		int newline = super.appendLine();

		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < getColumnCount() - 1; i++) {
			sb.append(",");
		}
		setLine(newline, sb.toString());

		return newline;
	}

	/**
	 * Construct CSVAccessor object
	 *
	 */
	public CSVAccessor() {

	}

	/**
	 * Constructs a CSVFileAccessor by the csv filename
	 *
	 * @param filename
	 *            the csv filename
	 */
	public CSVAccessor(String filename) {
		super(filename);
	}

	/**
	 * Determine the line is comment
	 *
	 * @param lineNumber
	 *            the line number in the CSV file, based 0
	 * @return true if the line is a CSV commen line (the first not whitespace
	 *         character is '#' or ';'), false otherwise.
	 */
	public boolean isCommentLine(int lineNumber) {
		String line = getLine(lineNumber).trim();
		return line.startsWith("#") || line.startsWith(";");
	}

	/**
	 * Determine the line is a value line.
	 *
	 * @param lineNumber
	 *            the line number in the CSV file, based 0
	 * @return true if the line neither a comment line nor a blank line, false
	 *         otherwsie
	 */
	public boolean isValueLine(int lineNumber) {
		return !isCommentLine(lineNumber) && !isBlankLine(lineNumber);
	}

	/**
	 * Return the column value of the line.
	 *
	 * @param lineNumber
	 *            the line number in the CSV file, based 0
	 * @param colIndex
	 *            the column index, based 0
	 * @return the column value, return null if the line is not a value line or
	 *         colIndex exceeds the maximize the column count of this line.
	 */
	public String getColumn(int lineNumber, int colIndex) {
		if (isValueLine(lineNumber)) {
			String[] columns = StringUtil.splitString(getLine(lineNumber), ",",	-1);
			if (colIndex >= 0 && colIndex < columns.length) {
				return columns[colIndex];
			}
		}

		return null;
	}

	/**
	 * Set the column value of the specified line. If the line is not a value
	 * line or the colndex excceds the column count,this method do nothing.
	 *
	 * @param lineNumber
	 *            the line number in the CSV file, based 0
	 * @param colIndex
	 *            the column index, based 0
	 * @param value
	 */
	public void setColumn(int lineNumber, int colIndex, String value) {
		// if (!isValueLine(lineNumber))
		if (isCommentLine(lineNumber)) {
			return;
		}

		String[] columns = getLine(lineNumber).split(",", -1);
		// String[] columns = StringUtil.splitString(getLine(lineNumber), ",",
		// -1);

		if (colIndex >= 0 && colIndex < columns.length) {
			columns[colIndex] = (value == null) ? "" : value;
		}

		// merge the String array to a line string
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < columns.length; i++) {
			sb.append(columns[i]);
			if (i != columns.length - 1) {
				sb.append(",");
			}
		}
		lines.set(lineNumber, sb.toString());
	}

// 2012/04/24 Y.Kowase Mantis2178 Add ->
	// csvの切り出し文字を変更
	public String getColumnEX(int lineNumber, int colIndex) {
		if (isValueLine(lineNumber)) {
			String[] columns = StringUtil.splitString(getLine(lineNumber), ",",	-1);
			if (colIndex >= 0 && colIndex < columns.length) {
				String ss = new String();
				ss = columns[colIndex];
				if( ss.length() == 0) return columns[colIndex];
				if( columns[colIndex].charAt(0) == '\"' &&
					columns[colIndex].charAt(columns[colIndex].length()-1) == '\"'){
					String splitcol = columns[colIndex].substring(1, columns[colIndex].length()-1);
					return splitcol;
				}
				return columns[colIndex];
			}
		}

		return null;
	}

	// csvの切り出し文字を変更
	public int getColumnCountEX(int lineNumber) {
		String line = getLine(lineNumber);
		if (isValueLine(lineNumber)) {
			int count = 1;
			int startIndex = 0;
			int pos = -1;
//			while (-1 != (pos = line.indexOf("\",\"", startIndex)) ||
//					-1 != (pos = line.indexOf(",", startIndex))) {
			while (-1 != (pos = line.indexOf(",", startIndex))) {
				startIndex = pos + 1;
				count++;
			}

			return count;
		} else {
			return -1;
		}
	}
// 2012/04/24 Y.Kowase Mantis2178 Add <-

	/**
	 * Return the number of the columns in the line.
	 *
	 * @param lineNumber
	 *            the line number in the CSV file, based 0
	 * @return the number of the columns, -1 if the line is not a value line.
	 */
	public int getColumnCount(int lineNumber) {
		String line = getLine(lineNumber);
		if (isValueLine(lineNumber)) {
			int count = 1;
			int startIndex = 0;
			int pos = -1;
			while (-1 != (pos = line.indexOf(",", startIndex))) {
				startIndex = pos + 1;
				count++;
			}

			return count;
		} else {
			return -1;
		}
	}

	/**
	 * @return Returns the columnCount.
	 */
	public int getColumnCount() {
		return columnCount;
	}

	/**
	 * @param columnCount
	 *            The columnCount to set.
	 */
	public void setColumnCount(int columnCount) {
		this.columnCount = columnCount;
	}

	/**
	 * Return the index of the key column, based 0
	 *
	 * @return Returns the keyIndex.
	 */
	public int getKeyIndex() {
		return keyIndex;
	}

	/**
	 * Set the index of the key column, based 0. The key column is used to find
	 * the specified line.
	 *
	 * @param keyIndex
	 *            The keyIndex to set.
	 */
	public void setKeyColumn(int keyIndex) {
		this.keyIndex = keyIndex;
	}

	/**
	 * Find the line matched the key value
	 *
	 * @param keyString
	 *            the key value
	 * @return the line number if found, -1 otherwise
	 */
	public int find(String keyString) {
		if (null == keyString) {
			return -1;
		}

		// find the user, if not found, throws a UserNotFoundException
		//
		for (int i = 0; i < getLineCount(); i++) {
			if (isValueLine(i) && keyString.equals(getColumn(i, keyIndex))) {
				return i;
			}
		}

		return -1;
	}
}